//
//  Base64.m
//  FaceToucher
//
//  Created by Jesse Bjarne Chiang on 10-8-1.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "Base64.h"b

static char base64EncodingTable[64] =
{
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
	'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};

@implementation Base64

- (id)init {
	if ((self = [super init])) {
		
	}
	return self;
}

//base 64 encoding
//length 参数代表，data数据的长度
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length
{
    unsigned long ixtext, lentext;
    long ctremaining;
    unsigned char input[3], output[4];
    short i, charsonline = 0, ctcopy;
    const unsigned char *raw;
    NSMutableString *result;
    
    lentext = [data length];  
    if (lentext < 1)
        return @"";
    result = [NSMutableString stringWithCapacity: lentext];
    raw = [data bytes];
    ixtext = 0;  
    
    while (YES)
    {
        ctremaining = lentext - ixtext;
        if (ctremaining <= 0)  
            break;         
        for (i = 0; i < 3; i++)
        {  
            unsigned long ix = ixtext + i;
            if (ix < lentext)
                input[i] = raw[ix];
			else
				input[i] = 0;
		}
        
        output[0] = (input[0] & 0xFC) >> 2;
        output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
        output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
        output[3] = input[2] & 0x3F;
        ctcopy = 4;
        switch (ctremaining)
        {
            case 1:  
                ctcopy = 2;  
                break;
            case 2:  
                ctcopy = 3;  
                break;
        }
        
        for (i = 0; i < ctcopy; i++)
            [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];
        
        for (i = ctcopy; i < 4; i++)
            [result appendString: @"="];
        
        ixtext += 3;
        charsonline += 4;
        
        if ((length > 0) && (charsonline >= length))
            charsonline = 0;
	}
	return result;
}

//base64 decoding
//string代表被编码的数据字符串
+ (NSData *) base64DataFromString: (NSString *)string
{
    unsigned long ixtext, lentext;
    unsigned char ch, input[4], output[3];
    short i, ixinput;
    BOOL flignore, flendtext = NO;
    const char *temporary;
    NSMutableData *result;
    
    if (!string)
        return [NSData data];
    
    ixtext = 0;
    temporary = [string UTF8String];
    lentext = [string length];
    result = [NSMutableData dataWithCapacity: lentext];
    ixinput = 0;
    while (YES)
    {
        if (ixtext >= lentext)
            break;
        ch = temporary[ixtext++];
        flignore = NO;
        if ((ch >= 'A') && (ch <= 'Z'))
            ch = ch - 'A';
		else if ((ch >= 'a') && (ch <= 'z'))
			ch = ch - 'a' + 26;
		else if ((ch >= '0') && (ch <= '9'))
			ch = ch - '0' + 52;
		else if (ch == '+')
			ch = 62;
		else if (ch == '=')
			flendtext = YES;
		else if (ch == '/')
			ch = 63;
		else
			flignore = YES;  
		
		if (!flignore)
		{
			short ctcharsinput = 3;
			BOOL flbreak = NO;
			
			if (flendtext)
			{
				if (ixinput == 0)
					break;                 
				if ((ixinput == 1) || (ixinput == 2))
					ctcharsinput = 1;
				else
					ctcharsinput = 2;
				ixinput = 3;
				flbreak = YES;
			}
			
			input[ixinput++] = ch;
			
			if (ixinput == 4)
			{
				ixinput = 0;
				
				output[0] = (input[0] << 2) | ((input[1] & 0x30) >> 4);
				output[1] = ((input[1] & 0x0F) << 4) | ((input[2] & 0x3C) >> 2);
				output[2] = ((input[2] & 0x03) << 6) | (input[3] & 0x3F);
				for (i = 0; i < ctcharsinput; i++)
					[result appendBytes: &output[i] length: 1];
			}
			
			if (flbreak)
				break;
		}
    }
    return result;
} 

- (void)dealloc {
	[super dealloc];
}

@end
